<template>
  <div class="phone-code">
    <el-form :model="formData" ref="phoneForm" :rules="rules" @validate="validator" :show-message="false">
      <el-form-item v-if="layout.includes('phone')" prop="phoneNumber" ref="phoneNumber" :error="phoneError">
        <el-input v-model.trim="formData.phoneNumber"
          @focus="clearValidate('phoneNumber')"
          :key="11"
          maxlength="11"
          :readonly="phoneDisable"
          placeholder="手机号" />
      </el-form-item>

      <el-form-item v-if="layout.includes('phone2')" prop="phoneNumber" ref="phoneNumber" :error="phoneError">
        <phone-input v-model="formData.phoneNumber"
          :clearValidate="true"
          @selectPhone="selectPhone"
          @focus="phoneFocus" />
      </el-form-item>

      <el-form-item v-if="layout.includes('code')" prop="code" :error="codeError">
        <el-input placeholder="验证码"
          @focus="clearValidate('code')"
          :maxlength="6"
          v-model.trim="formData.code"
          @keydown.enter="emitHandleEnter">
          <template #suffix>
            <div
              class="send-btn"
              :class="{disabled:codeDisabled}"
              @click="handleClickCode">
              {{btnText}}
            </div>
          </template>
        </el-input>
      </el-form-item>
      <el-form-item v-if="layout.includes('pwd')" prop="pwd">
        <pwd-input v-model.trim="formData.pwd"
           :placeholder="pwdPlaceholder"
           type="password"
           autocomplete='new-password'
           maxlength="16"
           @focus="clearValidate('pwd')">
         </pwd-input>
      </el-form-item>
      <el-form-item  v-if="layout.includes('pwd2')" prop="pwd2">
        <pwd-input v-model.trim="formData.pwd2"
           placeholder="请再次输入密码"
           type="password"
           autocomplete='new-password'
           maxlength="16"
           @focus="clearValidate('pwd2')"
           @handleEnter="emitHandleEnter">
         </pwd-input>
      </el-form-item>
    </el-form>
    <ImgCaptchaDialog v-model:visible="imgCaptchaVisible" ref="ImgCaptchaDialog" @onSendSms="sendSms"/>
  </div>
</template>
<script lang="ts">
import PhoneInput from './phone-input.vue'
import ImgCaptchaDialog from './img-captcha-dialog.vue'
import { sendSms } from '@/api/login'
import { debounce } from '@/utils'
import PsMessage from "@/components/message/index";
// @ts-ignore
import { validPhone, validPhoneCode, validPwd } from '@/utils/validate'

export default {
  name: 'PhoneForm',
  components: {
    ImgCaptchaDialog,
    PhoneInput
  },
  model: {
    prop: 'form',
    event: 'change'
  },
  props: {
    type: {
      type: String,
      default: ''
    },
    value: {
      type: Object,
      default: () => ({})
    },
    form: {
      type: Object,
      default: () => ({})
    },
    phoneDisable: {
      type: Boolean,
      default: false
    },
    layout: {
      type: Array,
      default: () => ['phone', 'code']
    },
    pwdPlaceholder: {
      type: String,
      default: '请输入密码'
    },
    errMsgOffset: {
      type: Number,
      default: 189
    }
  },
  emits: ['handleEnter'],
  data () {
    return {
      phoneError: '',
      codeError: '',
      codeSending: false,
      codeTime: 0,
      handleCount: 0, // 已发送验证码次数
      imgCaptchaVisible: false,
      formData: {
        phoneNumber: '',
        code: '',
        codeID: '',
        pwd: '',
        pwd2: ''
      }
    }
  },
  computed: {
    rules () {
      return {
        phoneNumber: [
          {
            trigger: [],
            validator: (rule: any, value: any, cb: any) => {
              if (this.type === 'pwd-login') {
                return value ? cb() : cb(new Error('请输入手机号码'))
              }

              if (validPhone(value)) {
                cb()
              } else {
                const errMsg = value ? '手机号码无效！' : '请输入手机号码'
                cb(new Error(errMsg))
              }
            }
          }
        ],
        code: [
          {
            trigger: [],
            validator: (rule: any, value: any, cb: any) => {
              if (validPhoneCode(value)) {
                cb()
              } else {
                const errMsg = value ? '请输入正确的验证码' : '请输入验证码'
                cb(new Error(errMsg))
              }
            }
          }
        ],
        pwd: [
          {
            trigger: [],
            validator: (rule: any, value: any, cb: any) => {
              if (!(/^.{8,16}$/.test(value))) {
                cb(new Error('密码长度为8位到16位'))
              } else if (!validPwd(value)) {
                cb(new Error('密码必须包含数字和字母'))
              } else {
                cb()
              }
            }
          }
        ],
        pwd2: [
          {
            trigger: [],
            validator: (rule: any, value: any, cb: any) => {
              if (!value) {
                cb(new Error('请再次输入新密码'))
              } else if (value !== this.formData.pwd) {
                cb(new Error('密码不一致，请重新输入！'))
              } else {
                cb()
              }
            }
          }
        ]
      }
    },
    btnText () {
      if (this.codeSending) {
        return '发送中'
      }
      if (this.codeTime) {
        return '重新发送（' + this.codeTime + 's）'
      }
      if (this.handleCount) {
        return '重新发送'
      }
      return '获取验证码'
    },
    codeDisabled () {
      return ((this.layout.includes('phone') || this.layout.includes('phone2')) && !validPhone(this.formData.phoneNumber)) || (this.codeTime || this.codeSending)
    }
  },
  created () {
    this.showValidateErrMsg = debounce((errMsg: any) => {
      PsMessage({ message: errMsg, offset: this.errMsgOffset })
    }, 1000, true)
  },
  unmounted () {
    clearInterval(this.timerId)
  },
  methods: {
    /**
     * 表单验证结果回调事件
     */
    validator (prop: any, valid: any, errMsg: any) {
      // validator 中延迟检验，可中断账号弹框切换后还显示错误提示
      if (!errMsg) {
        return
      }
      this.showValidateErrMsg(errMsg)
    },
    /**
     * 清除验证结果
     */
    clearValidate (props: any) {
      this.$refs.phoneForm.clearValidate(props)
    },
    handleClickCode () {
      if (this.codeDisabled) return
      this.sendSms()
    },
    /**
     * 发送手机验证码
     * @param {Object} 附加参数
     */
    sendSms (obj = {}) {
      const params = Object.assign({
        'phoneNumber': this.formData.phoneNumber,
        'type': 'phone',
        'eMail': ''
      }, obj)
      this.codeSending = true
      sendSms(params, { offset: 169 }).then((res: any = {}) => {
        this.codeSending = false
        const data = res.data || {}
        if (data.Verify === false) {
          this.showValidateErrMsg('图片验证码错误，请重新输入')
          this.$refs.ImgCaptchaDialog && this.$refs.ImgCaptchaDialog.getCaptcha()
          return
        }
        this.imgCaptchaVisible = false
        this.showValidateErrMsg('验证码已发送至您的手机')
        // eslint-disable-next-line vue/no-mutating-props
        this.formData.codeID = data.ID
        this.handleCount++
        this.codeTime = 60
        this.timerId = setInterval(() => {
          this.codeTime--
          if (this.codeTime <= 0) {
            clearInterval(this.timerId)
            this.codeTime = 0
          }
        }, 1000)
      }).catch(e => {
        this.codeSending = false
        if (e && e.code === 451) {
          this.imgCaptchaVisible = true
        }
      })
    },
    phoneFocus () {
      !this.type && this.clearValidate('phoneNumber')
      this.$PsMessage.closeAll()
    },
    /**
     * 选中手机账号记录列表
     * @param {String} data
     */
    selectPhone (data: any) {
      if (data.p && this.type === 'pwd-login') {
        // eslint-disable-next-line vue/no-mutating-props
        this.formData.pwd = data.p.slice(0, 16)
        this.$nextTick(() => {
          // eslint-disable-next-line vue/no-mutating-props
          this.formData.md5Pwd = data.p
        })
        // eslint-disable-next-line vue/no-mutating-props
        this.formData.isRemberPwd = true
      } else {
        // this.form.isRemberPwd = false
      }
    },

    validate () {
      return new Promise((resolve, reject) => {
        this.$refs.phoneForm.validate((valid: any) => {
          if (valid) {
            resolve(this.formData)
          } else {
            reject(valid)
          }
        })
      })
    },
    resetFields () {
      clearInterval(this.timerId)
      this.codeTime = 0
      this.handleCount = 0
      this.$refs.phoneForm.resetFields()
    },
    emitHandleEnter () {
      this.$emit('handleEnter')
    }
  }
}
</script>
<style lang="scss" scoped>
.phone-code {
  width: 198px;
  margin: 0 auto;
}

.send-btn {
  font-size: 14px;
  font-weight: 400;
  color: var(--el-text-color-placeholder);
  margin-right: 10px;
  user-select: none;
  cursor: no-drop;
  &:not(.disabled) {
    cursor: pointer;
    color: var(--el-color-primary);
    &:hover {
      opacity: 0.8;
    }
  }
}
</style>
